import Snake from './Snake'
import Food from './Food'
import Scoreboard from './Scoreboard'
import InfoDialog from './InfoDialog'
import ButtonBoard from './ButtonBoard'
import ModeBoard from './ModeBoard'
import { addSlidingEventListener } from '../utils/index'

type Direction = 'up' | 'down' | 'left' | 'right'
type GameStatus = 'no_start' | 'have_in_hand' | 'paused' | 'prepare-start'
class GameControl {
  private gameStatus: GameStatus = 'no_start' //当前游戏的状态
  private moveDirection: Direction = 'right' //蛇当前的移动方向
  private GameSuccess = false
  constructor() {
    // 绑定事件
    this.bindEvents()
  }

  /**
   * 当前游戏的状态
   */
  get currentGameStatus() {
    return this.gameStatus
  }

  /**
   * 移动🐍
   * @param mode
   */
  private startMoveSnake() {
    const assistMove = () => {
      //也可以使用window.setInterval
      //但是我们更希望当检查任务完成后再进行下一下移动,这样可以避免一些bug
      const timer = window.setTimeout(() => {
        Snake.move(this.moveDirection)
        //检查任务
        this.checkIfItHitTheWall()
        this.checkCollisionWithTheBody()
        this.checkIfFoodHasBeenEaten()
        this.checkGameSuccessful()
        if (this.currentGameStatus == 'have_in_hand') {
          assistMove()
        }

        window.clearTimeout(timer)
      }, ModeBoard.timeInterval)
    }

    //只有在蛇没有移动的情况下,才能开始移动
    if (this.currentGameStatus != 'have_in_hand') {
      this.gameStatus = 'have_in_hand'
      assistMove()
    }
  }

  /**
   * 点击开始游戏按钮
   */
  private onGameStart() {
    this.startMoveSnake()
    //隐藏按钮
    ButtonBoard.setBtnVisible('startBtnEle', false)
    //显示按钮
    ButtonBoard.setBtnVisible('suspendBtnEle', true)
  }

  /**
   * 点击暂停按钮
   */
  private onGameSuspend() {
    this.gameStatus = 'paused'

    //隐藏按钮
    ButtonBoard.setBtnVisible('suspendBtnEle', false)
    //显示按钮
    ButtonBoard.setBtnVisible('continueBtnEle', true)
  }

  /**
   * 点击继续按钮
   */
  private onGameContinue() {
    this.startMoveSnake()
    //隐藏按钮
    ButtonBoard.setBtnVisible('continueBtnEle', false)
    //显示按钮
    ButtonBoard.setBtnVisible('suspendBtnEle', true)
  }

  /**
   * 点击重新开始
   */
  private onGameRestart() {
    this.resetGameStatus()
  }

  /**
   * 处理键盘方向键按下
   */
  private onDirectionKeysDown(ev: KeyboardEvent) {
    const code = ev.code

    if (code === 'ArrowUp') {
      this.setMoveDirection('up')
    } else if (code === 'ArrowDown') {
      this.setMoveDirection('down')
    } else if (code === 'ArrowLeft') {
      this.setMoveDirection('left')
    } else if (code === 'ArrowRight') {
      this.setMoveDirection('right')
    } else {
      return
    }
    //默认在按下方向键以后就尝试开始移动
    if (this.currentGameStatus == 'no_start') {
      this.onGameStart()
    }
    if (this.currentGameStatus == 'paused') {
      this.onGameContinue()
    }
  }

  /**
   * 处理屏幕滑动事件
   */
  onSlidingEvent(direction: Direction) {
    this.setMoveDirection(direction)
    //默认在按下方向键以后就尝试开始移动
    if (this.currentGameStatus == 'no_start') {
      this.onGameStart()
    }
    if (this.currentGameStatus == 'paused') {
      this.onGameContinue()
    }
  }

  /**
   * 绑定事件
   */
  private bindEvents() {
    //开始按钮
    ButtonBoard.addEventHandlerForBtn(
      'startBtnEle',
      this.onGameStart.bind(this)
    )
    //暂停按钮
    ButtonBoard.addEventHandlerForBtn(
      'suspendBtnEle',
      this.onGameSuspend.bind(this)
    )

    // 继续按钮
    ButtonBoard.addEventHandlerForBtn(
      'continueBtnEle',
      this.onGameContinue.bind(this)
    )

    //重新开始按钮
    ButtonBoard.addEventHandlerForBtn(
      'restartBtnEle',
      this.onGameRestart.bind(this)
    )
    //处理键盘方向键按下
    window.addEventListener('keydown', this.onDirectionKeysDown.bind(this))

    //监听滑动事件
    addSlidingEventListener(this.onSlidingEvent.bind(this))
  }

  /**
   * 检查是否吃到食物
   */
  private checkIfFoodHasBeenEaten() {
    if (Snake.isEatFood()) {
      //改变食物位置
      Food.changePostion()
      //添加蛇的身体
      Snake.addBody(this.moveDirection)
      //积分板加分
      Scoreboard.updateInfo()
    }
  }

  /**
   * 检查是否撞墙
   */
  private checkIfItHitTheWall() {
    if (Snake.isHitTheWall()) {
      InfoDialog.setVerVisible(true, '游戏结束!', '撞到墙了呦')
      this.onGameFailed()
    }
  }

  /**
   * 检查是否碰撞身体
   */
  private checkCollisionWithTheBody() {
    if (Snake.isCollidedTheBody()) {
      InfoDialog.setVerVisible(true, '游戏结束!', '你吃到身体啦')
      this.onGameFailed()
    }
  }

  /**
   * 处理游戏失败
   */
  private onGameFailed() {
    // 暂停蛇的移动
    this.gameStatus = 'prepare-start' //准备开始
    //隐藏按钮
    ButtonBoard.setBtnVisible('suspendBtnEle', false)
    ButtonBoard.setBtnVisible('continueBtnEle', false)
    //显示重新开始按钮
    ButtonBoard.setBtnVisible('restartBtnEle', true)
  }

  /**
   * 检查游戏是否成功
   */
  private checkGameSuccessful() {
    if (Scoreboard.challengeSuccess()) {
      //完成任务后玩家任然可以继续游戏,直到死亡
      if (!this.GameSuccess) {
        InfoDialog.setVerVisible(true, '挑战成功!', '恭喜你完成了游戏任务')
        //游戏暂停,玩家可以选择继续
        this.onGameSuspend()
        this.GameSuccess = true
      }
    }
  }

  /**
   * 设置移动方向
   * @param direction
   * @returns
   */
  private setMoveDirection(direction: Direction) {
    // 有身体的时候，蛇是不能够回头的
    if (Snake.snakeLength > 1) {
      if (
        (this.moveDirection == 'down' && direction == 'up') ||
        (this.moveDirection == 'left' && direction == 'right') ||
        (this.moveDirection == 'right' && direction == 'left') ||
        (this.moveDirection == 'up' && direction == 'down')
      ) {
        return
      }
    }
    this.moveDirection = direction
  }

  /**
   * 重设游戏状态
   */
  private resetGameStatus() {
    //重设状态
    this.gameStatus = 'no_start'
    Snake.resetStatus()
    Food.resetStatus()
    Scoreboard.resetStatus()
    ButtonBoard.resetStatus()
  }
}
export default new GameControl()
